﻿using MCPlatform.Dxf.Entities;
using MCPlatform.Dxf.Utils;
using netDxf;
using netDxf.Entities;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Media;

namespace MCPlatform.Dxf.Entities
{
    public class ArcPathEntity : PathEntityBase
    {

        /// <summary>
        /// 默认用于生成圆弧路径的点数。
        /// </summary>
        private const int DefaultNumPoints = 10;

        #region Properties

             

        /// <summary>
        /// 圆弧的半径。
        /// </summary>
        public double Radius { get; }

      

        /// <summary>
        /// 圆弧的起始角度（以度为单位）。
        /// </summary>
        public double StartAngle { get; }

        /// <summary>
        /// 圆弧的结束角度（以度为单位）。
        /// </summary>
        public double EndAngle { get; }

       
        public Arc Arc {get; }


        #endregion


        /// <summary>
        /// 初始化圆弧路径实体。
        /// </summary>
        /// <param name="arc">用于创建圆弧路径实体的DXF圆弧。</param>
        public ArcPathEntity(Arc arc)
        {
           
           this.Arc = arc;

            // 将DXF圆弧的中心点转换为Vector3类型。
            Center = new Vector3(arc.Center.X, arc.Center.Y, arc.Center.Z);
            // 设置圆弧的半径。
            Radius = arc.Radius;
            // 标准化起始角度，确保其在0到360度之间。
            StartAngle = NormalizeAngle(arc.StartAngle);
            // 标准化结束角度，确保其在0到360度之间。
            EndAngle = NormalizeAngle(arc.EndAngle);
            // 根据起始角度、结束角度和默认点数生成圆弧路径上的点列表。
            //PathPoints = GenerateArcPoints(Center, Radius, StartAngle, EndAngle, DefaultNumPoints);
            StartPoint = CalculateArcPoint((Vector3)Center, Radius, StartAngle);
            EndPoint = CalculateArcPoint((Vector3)Center, Radius, EndAngle);
            MidPoint = CalculateArcPoint((Vector3)Center, Radius, (StartAngle + EndAngle) / 2);
            Type = arc;
            Handle = arc.Handle;
            Length = CalculateCircumference(StartAngle, EndAngle);

            DrawShape(arc);
        }

        public void DrawShape(Arc? arc = null, float scaleX = 1, float scaleY = 1, float strokeThickness = 1)
        {
            if (arc == null)
            {
                arc = this.Arc;
            }

            System.Windows.Shapes.Path path = new System.Windows.Shapes.Path
            {
                Stroke = Utility.ConvertAciColorToBrush(arc.Color),
                StrokeThickness = Utility.GetNumberFromTextToFloat(arc.Lineweight.ToString(),arc.Layer.Lineweight.ToString())?? strokeThickness,
            };

            System.Windows.Point endPoint = new System.Windows.Point(
                (arc.Center.X + Math.Cos(arc.EndAngle * Math.PI / 180) * arc.Radius) * scaleX,
                (arc.Center.Y + Math.Sin(arc.EndAngle * Math.PI / 180) * arc.Radius) * scaleY);
            System.Windows.Point startPoint = new System.Windows.Point(
                (arc.Center.X + Math.Cos(arc.StartAngle * Math.PI / 180) * arc.Radius) * scaleX,
                (arc.Center.Y + Math.Sin(arc.StartAngle * Math.PI / 180) * arc.Radius) * scaleY);

            ArcSegment arcSegment = new ArcSegment
            {
                Point = endPoint,
                Size = new System.Windows.Size(arc.Radius * scaleX, arc.Radius * scaleY)
            };

            double sweep = (arc.EndAngle - arc.StartAngle + 360) % 360;
            arcSegment.IsLargeArc = sweep >= 180;

            // 根据StartAngle和EndAngle来判断顺时针或逆时针
            //if (IsCounterclockwise(arc))
            //{
            //    arcSegment.SweepDirection = SweepDirection.Counterclockwise;
            //}
            //else
            //{
            //    arcSegment.SweepDirection = SweepDirection.Clockwise;
            //}

            arcSegment.SweepDirection = SweepDirection.Clockwise;

            PathGeometry geometry = new PathGeometry();
            PathFigure pathFigure = new PathFigure
            {
                StartPoint = startPoint
            };
            pathFigure.Segments.Add(arcSegment);
            geometry.Figures.Add(pathFigure);

            path.Data = geometry;
            path.IsHitTestVisible = false;
        

            this.Shape = path;

            this.Shape.Tag = arc.Handle;
        }

        public static bool IsCounterclockwise(Arc arc)
        {
            var startAngleDegrees = arc.StartAngle;
            var endAngleDegrees = arc.EndAngle;


            if (arc.StartAngle >= arc.EndAngle)
            {
                //结束角度
                endAngleDegrees = arc.EndAngle + 360;
            }
           
                   

            PointD startPoint = RevolveTwoDimensionChange(new PointD(arc.Center.X, arc.Center.Y),
                                                                       new PointD(arc.Radius, 0),
                                                                      (double)AngleToRad(startAngleDegrees));

            PointD endPoint = RevolveTwoDimensionChange(new PointD(arc.Center.X, arc.Center.Y),
                                                                   new PointD(arc.Radius, 0),
                                                                   (double)AngleToRad(endAngleDegrees));

           
            //获取中点到开始点OA的向量
            PointD OA = TwoPointToVector(new PointD(startPoint.X, startPoint.Y), new PointD(arc.Center.X, arc.Center.Y));
            //获取中点到结束点OB的向量
            PointD OB = TwoPointToVector(new PointD(endPoint.X, endPoint.Y), new PointD(arc.Center.X, arc.Center.Y));

            //圆弧方向
            return VectorInculedAngle(OB, OA) < 0 ? true : false;

           
        }

        /// <summary>
        /// 角度转弧度
        /// </summary>
        /// <param name="angle">角度</param>
        /// <returns>返回弧度</returns>
        public static double AngleToRad(double angle)
        {
            return angle * Math.PI / 180;
        }

        /// <summary>
        /// 旋转二维坐标转换
        /// </summary>
        /// <param name="center">中心点</param>
        /// <param name="orgPoint">起始坐标点</param>
        /// <param name="radian">旋转弧度</param>
        /// <returns></returns>
        public static PointD RevolveTwoDimensionChange(PointD center, PointD orgPoint, double radian)
        {
            //X'=Xr+(X-Xr)COSa-(Y-Yr)SINa
            //Y'=Yr+(X-Xr)SINa+(Y-Yr)COSa
            // X',Y' 旋转后的坐标  Xr,Yr 旋转中心坐标  X,Y当前坐标

            //结果点声明实例化
            PointD resultPoint = new PointD();

            double cos = Math.Round(Math.Cos(radian), 7);
            double sin = Math.Round(Math.Sin(radian), 7);
            //计算旋转后的X点
            resultPoint.X = center.X + (orgPoint.X) * cos - (orgPoint.Y) * sin;
            //计算旋转后的Y点
            resultPoint.Y = center.Y + (orgPoint.Y) * cos + (orgPoint.X) * sin;

            return resultPoint;
        }


        /// <summary>
        /// 两点的向量 a结束点 b开始点
        /// </summary>
        /// <param name="a">结束点a</param>
        /// <param name="b">开始点b</param>
        /// <returns>返回向量</returns>
        public static PointD TwoPointToVector(PointD a, PointD b)
        {
            return new PointD(a.X - b.X, a.Y - b.Y);
        }

        public static double RadToAngle(double rad)
        {
            return rad * 180 / Math.PI;
        }
        public static double TwoSquare(double a, double b)
        {
            return Math.Pow(a, 2) + Math.Pow(b, 2);
        }

       

        /// <summary>
        /// 根据圆心、半径和角度，计算圆弧上的点。
        /// </summary>
        /// <param name="center">圆心</param>
        /// <param name="radius">半径</param>
        /// <param name="angle">角度</param>
        /// <returns>圆弧上的点</returns>
        private Vector3 CalculateArcPoint(Vector3 center, double radius, double angle)
        {
            double radians = angle * (Math.PI / 180);
            double x = center.X + radius * Math.Cos(radians);
            double y = center.Y + radius * Math.Sin(radians);
            return new Vector3(x, y, center.Z);
        }

        /// <summary>
        /// 根据给定的圆心和半径，以及起始和结束角度，生成圆弧路径上的点列表。
        /// </summary>
        /// <param name="center">圆弧的中心点。</param>
        /// <param name="radius">圆弧的半径。</param>
        /// <param name="startAngle">圆弧的起始角度（以度为单位）。</param>
        /// <param name="endAngle">圆弧的结束角度（以度为单位）。</param>
        /// <param name="numPoints">圆弧路径上点的数量。</param>
        /// <returns>圆弧路径上的点列表。</returns>
        private static List<Vector3> GenerateArcPoints(Vector3 center, double radius, double startAngle, double endAngle, int numPoints)
        {
            // 初始化圆弧路径上的点列表。
            List<Vector3> arcPoints = new List<Vector3>();
            // 计算每个角度步长。
            double angleStep = (endAngle - startAngle) / (numPoints - 1);
            // 将角度转换为弧度的系数（只计算一次以提高性能）。
            double radiansPerDegree = Math.PI / 180;
            // 遍历每个角度点，计算对应的坐标并添加到列表中。

            for (int i = 0; i < numPoints; i++)
            {
                // 计算当前角度。
                double currentAngle = startAngle + i * angleStep;
                // 根据当前角度和半径计算x和y坐标。
                double x = center.X + radius * Math.Cos(currentAngle * radiansPerDegree);
                double y = center.Y + radius * Math.Sin(currentAngle * radiansPerDegree);
                // 创建一个新的Vector3点，并添加到列表中。
                arcPoints.Add(new Vector3(x, y, 0));
            }
            // 返回生成的圆弧路径点列表。
            return arcPoints;
        }

        /// <summary>
        /// 将角度标准化为0到360度之间的值。
        /// </summary>
        /// <param name="angle">待标准化的角度。</param>
        /// <returns>标准化后的角度。</returns>
        private static double NormalizeAngle(double angle)
        {
            // 如果角度小于0，则加上360的倍数直到它大于或等于0。
            while (angle < 0) angle += 360;
            //如果角度大于或等于360，则减去360的倍数直到它小于360。
            while (angle >= 360) angle -= 360;
            // 返回标准化后的角度。
            return angle;
        }

        /// <summary>  
        /// 根据给定的起始角度和结束角度计算圆弧的周长。  
        /// </summary>  
        /// <param name="startAngle">圆弧的起始角度（以度为单位）</param>  
        /// <param name="endAngle">圆弧的结束角度（以度为单位）</param>  
        /// <returns>给定角度范围内的圆弧周长</returns>  
        public double CalculateCircumference(double startAngle, double endAngle)
        {
            double startAngleInRadians = startAngle * (Math.PI / 180);
            double endAngleInRadians = endAngle * (Math.PI / 180);
            double centralAngleInRadians = endAngleInRadians - startAngleInRadians;

            // 如果圆心角大于 2π，则取模 2π，因为超过一圈的部分对周长没有贡献  
            if (Math.Abs(centralAngleInRadians) > Math.PI * 2)
            {
                centralAngleInRadians = centralAngleInRadians % (Math.PI * 2);
                if (centralAngleInRadians < 0)
                {
                    centralAngleInRadians += Math.PI * 2;
                }
            }

            // 计算给定角度范围内的圆弧周长，周长乘以圆弧所占的比例即得
            double circumference = 2 * Math.PI * Radius * Math.Abs(centralAngleInRadians / (2 * Math.PI));
            return circumference;
        }

        /// <summary>
        /// 求两向量夹角
        /// </summary>
        /// <param name="v1">结束向量A</param>
        /// <param name="v2">开始向量B</param>
        /// <returns></returns>
        public static double VectorInculedAngle(PointD A, PointD B)
        {
            double resultAngle = 0;

            if ((Math.Round(A.X, 3) == 0 && Math.Round(A.Y, 3) == 0) || (Math.Round(B.X, 3) == 0 && Math.Round(B.Y, 3) == 0)) return resultAngle;

            //COS=A.B/A*B
            //AB向量点积
            double abPoint = VectorDotProduct(A, B);
            //AB长度
            double ab = Math.Sqrt(TwoSquare(A.X, A.Y)) * Math.Sqrt(TwoSquare(B.X, B.Y));
            //角度余弦
            double cos = abPoint / ab;


            if (cos > 1) cos = 1;
            else if (cos < -1) cos = -1;
            resultAngle = RadToAngle(Math.Acos(cos));
            //resultAngle = Math.Acos(cos);
            //向量叉积
            double abCross = VectorCrossProduct(A, B);
            //向量叉积为负时为顺时针夹角
            if (abCross < 0) resultAngle = -resultAngle;

            return resultAngle;
        }

        /// <summary>
        /// 向量点积
        /// </summary>
        /// <param name="A">A向量</param>
        /// <param name="B">B向量</param>
        /// <returns>返回常数</returns>
        public static double VectorDotProduct(PointD A, PointD B)
        {
            return A.X * B.X + A.Y * B.Y;
        }

        /// <summary>
        /// 向量叉积 A结束向量 B开始向量
        /// </summary>
        /// <param name="A">A向量</param>
        /// <param name="B">B向量</param>
        /// <returns>返回向量C</returns>
        public static double VectorCrossProduct(PointD A, PointD B)
        {
            return A.X * B.Y - B.X * A.Y;
        }


    }

    public class PointD
    {
        /// <summary>
        /// X坐标
        /// </summary>
        public double X { get; set; }
        /// <summary>
        /// Y坐标
        /// </summary>
        public double Y { get; set; }

        public PointD()
        {
           
        }
        public PointD(double x, double y)
        {
            X = x;
            Y = y;
        }
    }
}

